#ifndef ROSIGNALCONNECTION_H
#define ROSIGNALCONNECTION_H
#include <functional>
#include <QVariant>
#include <QMetaObject>
#include <QObject>
#include <QMetaType>
#include <QList>
#include <QDebug>
//用于结合Qt信号槽连接的两大方式，得出更稳妥的连接方式
class QObject;
class QMetaMethod;

template<class T> using InvokeGenSeq = typename T::Type;

template<int...> struct IndexesList { using Type = IndexesList; };

template<int N, class S1, class S2> struct ConcatSeqImpl;

template<int N, int... I1, int... I2>
struct ConcatSeqImpl<N, IndexesList<I1...>, IndexesList<I2...>>
    : IndexesList<I1..., (N + I2)...> {};

template<int N, class S1, class S2>
using ConcatSeq = InvokeGenSeq<ConcatSeqImpl<N, S1, S2>>;

template<int N> struct GenSeq;
template<int N> using makeIndexSequence = InvokeGenSeq<GenSeq<N>>;

template<int N>
struct GenSeq : ConcatSeq<N / 2, makeIndexSequence<N / 2>, makeIndexSequence<N - N / 2>> {};

template<> struct GenSeq<0> : IndexesList<> {};
template<> struct GenSeq<1> : IndexesList<0> {};

template<int N>
struct Indexes { using Value = makeIndexSequence<N>; };

template<typename ...Args>
struct ArgList
{

};

class ROSignalConnection
{
public:
    class SlotInfo;
    class SignalInfo
    {
    public:
        SlotInfo to(QObject* obj);
        SlotInfo to();
    private:
        SignalInfo();
        QObject* obj;
        int signal;
        friend class ROSignalConnection;
        friend class SignalInfo;
    };

    class SlotInfo
    {
    private:

        template<int ... indexs, typename ...Args, typename Func>
        void
        InvokeFunctionImp(Func func,void** param, IndexesList<indexs...>, ArgList<Args...>) {
            func(*(typename std::remove_reference<Args>::type*)(param[indexs + 1])...);
        }

    public:
        QMetaObject::Connection on(const std::function<void(void** params)>& func,Qt::ConnectionType type);
        QMetaObject::Connection onVarList(std::function<void(const QVariantList& params)> func,Qt::ConnectionType type);

        template<typename ...Args>
        QMetaObject::Connection on(std::function<void(Args...)> func,Qt::ConnectionType type){
            QList<int> slotTypes = {QMetaType::fromType<Args>()...};
            auto signalTypes = getSignalTypeIds();
            if(!compareTypes(signalTypes,slotTypes))
            {
                qDebug()<<"connection failed slot type not compatable";
            }

            typedef typename GenSeq<sizeof...(Args)>::Type IndexList;

            return on([=](void** params){
                InvokeFunctionImp(func,params,IndexList(),ArgList<Args...>());
            },type);
        }
    private:
        bool compareTypes(const QList<int>& signalTypes,const QList<int>& slotTypes);

        QList<int> getSignalTypeIds();

    private:
        SignalInfo signalInfo;
        QObject* slotobj = nullptr;
        friend class SignalInfo;
    };

public:
    typedef ROSignalConnection ThisType;

    static SignalInfo connect(QObject* obj,int signal);
    static SignalInfo connect(QObject* obj,QMetaMethod signal);
};

#endif
